using System;
using System.Collections.Generic;
using MSOffice = Microsoft.Office.Core;
using MSOutlook = Microsoft.Office.Interop.Outlook;

namespace Microsoft.Sample.Outlook.Utility
{
    public enum CommandBarWindowType
    {
        ExplorersOnly,
        InspectorsOnly,
        ExplorersAndInspectors
    }

    public class CommandBarEventArgs : EventArgs
    {
        private MSOutlook.Inspector _inspector = null;
        private MSOutlook.Explorer _explorer = null;
        private MSOffice.CommandBar _bar = null;

        public MSOutlook.Inspector Inspector
        {
            get { return _inspector; }
        }

        public MSOutlook.Explorer Explorer
        {
            get { return _explorer; }
        }

        public MSOffice.CommandBar CommandBar
        {
            get { return _bar; }
        }

        public ItemAdapter CurrentItem
        {
            get
            {
                if (_explorer != null)
                {
                    try
                    {
                        if (_explorer.Selection.Count != 1)
                            return null;

                        return ItemAdapter.FromObject(_explorer.Selection[1]);
                    }
                    //In some cases, _explorer.Selection throws a COM exception.
                    //In those cases, there is no valid selection, so return null
                    catch (System.Runtime.InteropServices.COMException)
                    {
                        return null;
                    }
                }

                if (_inspector != null)
                    return ItemAdapter.FromObject(_inspector.CurrentItem);

                throw new ApplicationException("only one of _explorer or _inspector can be null");
            }
        }

        internal CommandBarEventArgs(WindowAdapter window, MSOffice.CommandBar bar)
        {
            _bar = bar;

            if (window.Explorer != null)
                _explorer = window.Explorer;
            else if (window.Inspector != null)
                _inspector = window.Inspector;
            else
                throw new ApplicationException("Invalid WindowAdapter passed to CommandBarEventArgs");
        }
    }

    public class BeforeShowCommandBarEventArgs : CommandBarEventArgs
    {
        private bool _visible;

        public bool Visible
        {
            get { return _visible; }
            set { _visible = value; }
        }

        private bool _enabled;

        public bool Enabled
        {
            get { return _enabled; }
            set { _enabled = value; }
        }
	

        internal BeforeShowCommandBarEventArgs(WindowAdapter window, MSOffice.CommandBar bar, bool visible, bool enabled)
            : base(window, bar)
        {
            _visible = visible;
            _enabled = enabled;
        }
    }

    public abstract class CommandBar
    {
        private CommandBarWindowType _windowType = CommandBarWindowType.ExplorersAndInspectors;
        
        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        private List<WindowAdapter> _listWindows = new List<WindowAdapter>();
        internal IList<WindowAdapter> Windows
        {
            get { return _listWindows; }
        }

        public event EventHandler<BeforeShowCommandBarEventArgs> BeforeShow;

        protected void FireBeforeShow(BeforeShowCommandBarEventArgs args)
        {
            if (BeforeShow == null)
                return;

            BeforeShow(this, args);
        }

        internal void ShowCommandBar(WindowAdapter window, MSOffice.CommandBar bar)
        {
            BeforeShowCommandBarEventArgs args = new BeforeShowCommandBarEventArgs(window, bar, true, true);
            FireBeforeShow(args);

            bar.Visible = args.Visible;
            bar.Enabled = true;

            foreach (MSOffice.CommandBarControl ctl in bar.Controls)
            {
                ctl.Enabled = args.Enabled;
            }
            
        }

        public CommandBar(string name)
        {
            _name = name;
        }

        public CommandBar(string name, CommandBarWindowType windowType)
        {
            _name = name;
            _windowType = windowType;
        }

        /// <summary>
        /// Attach this toolbar to the specified explorer window
        /// </summary>
        /// <param name="explorer"></param>
        public void Attach(MSOutlook.Explorer explorer)
        {
            if (_windowType == CommandBarWindowType.InspectorsOnly)
                return;

            //Newly created explorer windows (i.e. the parameter of the NewExplorer event) throw an exception
            //if you attempt to access their commandbars collection. The CommandBars property of the WindowAdapter
            //class swallows that exception and returns null instead. If the explorer window is new and the commandbars
            //collection isn't accessable, subscribe to the acitvate event and bind the toolbar there. Otherwise, bind 
            //the toolbar now.

            WindowAdapter window = new WindowAdapter(explorer);
            if (window.CommandBars != null)
            {
                DoAttach(window);
            }
            else
            {
                EventHandler onActivate = null;
                onActivate = delegate(object sender, EventArgs e)
                {
                    window.Activate -= onActivate;
                    DoAttach(window);
                };
                window.Activate += onActivate;
            }
        }

        /// <summary>
        /// Attach this toolbar to the specified inspector window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Attach(MSOutlook.Inspector inspector)
        {
            if (_windowType == CommandBarWindowType.ExplorersOnly)
                return;

            WindowAdapter window = new WindowAdapter(inspector);
            DoAttach(window);
        }

        private void DoAttach(WindowAdapter window)
        {
            window.Close += delegate(object sender, EventArgs args)
            {
                Detach(window);
            };

            Attach(window);
        }

        internal abstract void Attach(WindowAdapter window);
        internal abstract void Detach(WindowAdapter window);

    }
}
